package eu.winterwheels.enterprise.data;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.apache.commons.codec.binary.Base64;

import eu.winterwheels.enterprise.model.User;

@ApplicationScoped
public class UserRepository {

	@Inject
	private Logger log;

	@Inject
	private EntityManager em;

	public User findById(Long id) {
		return em.find(User.class, id);
	}

	/**
	 * Returns the user that matches the username and password.
	 * 
	 * @param username
	 * @param password
	 * @return User Returns the found user or null if not found.
	 */
	public User findByCredentials(String username, String password) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<User> criteria = cb.createQuery(User.class);
		Root<User> user = criteria.from(User.class);
		// Swap criteria statements if you would like to try out type-safe
		// criteria queries, a new
		// feature in JPA 2.0
		// criteria.select(User).where(cb.equal(User.get(User_.name), email));
		// criteria.select(user).where(cb.equal(user.get("username"),
		// username));

		criteria.select(user).where(cb.equal(user.get("username"), username),
				cb.equal(user.get("password"), encodePassword(password)));
		User qUser = null;
		try {
			qUser = em.createQuery(criteria).getSingleResult();
		} catch (NoResultException nre) {
			log.warning("A user was queried with username (" + username + ") and password ("
					+ encodePassword(password)+ ") that does not match a user account and password. " + nre.getMessage());
		}
		return qUser;
	}

	/**
	 * Encode the password with SHA-256.
	 * 
	 * @param password
	 *            The password to encode.
	 * @return String The binary value encoded with SHA-256.
	 */
	private String encodePassword(String password) {
		MessageDigest messageDigest = null;
		try {
			messageDigest = java.security.MessageDigest.getInstance("SHA-256");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		final byte bin[] = messageDigest.digest(password.getBytes());
		// System.out.println(Base64.encodeBase64String(bin));
		return Base64.encodeBase64String(bin);
	}

	public User findByEmail(String email) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<User> criteria = cb.createQuery(User.class);
		Root<User> user = criteria.from(User.class);
		// Swap criteria statements if you would like to try out type-safe
		// criteria queries, a new
		// feature in JPA 2.0
		// criteria.select(User).where(cb.equal(User.get(User_.name), email));
		criteria.select(user).where(cb.equal(user.get("email"), email));
		return em.createQuery(criteria).getSingleResult();
	}

	public List<User> findAllOrderedByName() {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<User> criteria = cb.createQuery(User.class);
		Root<User> user = criteria.from(User.class);
		// Swap criteria statements if you would like to try out type-safe
		// criteria queries, a new
		// feature in JPA 2.0
		// criteria.select(User).orderBy(cb.asc(User.get(User_.name)));
		criteria.select(user).orderBy(cb.asc(user.get("name")));
		return em.createQuery(criteria).getResultList();
	}
}
